﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.CodeDom;
using System.Xaml;
using System.ComponentModel;
using System.Reflection;
using System.Diagnostics;

namespace NeuroSpeech.XamlExtensions
{
    public class XamlItem
    {
        public XamlItem()
        {
            _Value = new XamlItemValue(this);
        }

        public string Depth {
            get {
                if (Parent == null)
                    return "|----";
                return "|----" + Parent.Depth;
            }
        }

        public NamespaceDeclaration[] Declarations;
        private XamlType _Type = null;
        public XamlType Type
        {
            get
            {
                return _Type;
            }
            set
            {
                _Type = value;
                if (_Type.UnderlyingType != null)
                {
                    Type[] types = _Type.UnderlyingType.GetInterfaces();
                    _SupportsInitialize = types.Any( x=>x.FullName=="System.ComponentModel.ISupportInitialize" );
                }
            }
        }
        public XamlMember Member;
        public string Name;
        public string Key;
        public string Variable;
        public CodeExpression TargetObject;
        public string TargetObjectString
        {
            get
            {
                return ToExpressionString(TargetObject);
            }
        }

        private string ToExpressionString(CodeExpression expr)
        {
            if (expr == null)
                return "";
            if (expr is CodeVariableReferenceExpression)
                return "this." + (expr as CodeVariableReferenceExpression).VariableName;
            if (expr is CodePropertyReferenceExpression)
            {
                CodePropertyReferenceExpression p = expr as CodePropertyReferenceExpression;
                return ToExpressionString(p.TargetObject) + "." + p.PropertyName;
            }
            return "";
        }
        public bool IsRoot = false;

        public XamlItem Parent { get; set; }

        public bool IsMemberProperty {
            get {
                return Member != null && Member.UnderlyingMember != null && Member.UnderlyingMember.MemberType == System.Reflection.MemberTypes.Property;
            }
        }

        public bool IsMemberMethod
        {
            get
            {
                return Member != null && Member.UnderlyingMember != null && Member.UnderlyingMember.MemberType == System.Reflection.MemberTypes.Method;
            }
        }

        public bool IsMemberField
        {
            get
            {
                return Member != null && Member.UnderlyingMember != null && Member.UnderlyingMember.MemberType == System.Reflection.MemberTypes.Field;
            }
        }

        public bool IsMemberEvent
        {
            get
            {
                return Member != null && Member.UnderlyingMember != null && Member.UnderlyingMember.MemberType == System.Reflection.MemberTypes.Event;
            }
        }

        public EventInfo MemberEvent {
            get {
                if (Member.UnderlyingMember == null)
                    return null;
                return Member.UnderlyingMember as EventInfo;
            }
        }

        public PropertyInfo MemberProperty
        {
            get {
                if (Member.UnderlyingMember == null)
                    return null;
                return Member.UnderlyingMember as PropertyInfo;
            }
        }

        public FieldInfo MemberField
        {
            get
            {
                if (Member.UnderlyingMember == null)
                    return null;
                return Member.UnderlyingMember as FieldInfo;
            }
        }

        public MethodInfo MemberMethod
        {
            get
            {
                if (Member.UnderlyingMember == null)
                    return null;
                return Member.UnderlyingMember as MethodInfo;
            }
        }

        public Type MemberType {
            get {
                if (IsMemberMethod)
                    return MemberMethod.ReturnType;
                if (IsMemberField)
                    return MemberField.FieldType;
                if (IsMemberProperty)
                    return MemberProperty.PropertyType;
                return null;
            }
        }

        private bool _SupportsInitialize = false;
        public bool SupportsInitialize
        {
            get
            {
                return _SupportsInitialize;
            }
        }

        public bool SupportInitializeAdded { get; set; }

        private XamlItemValue _Value;
        public XamlItemValue Value { 
            get {
                return _Value;
            } 
        }

        public bool IsValueCollection {
            get {
                return Value.Collection != null;
            }
        }

        public bool RequiresCasting(XamlCodeContext context)
        {
            Type type = MemberType;
            Type valueType = Value.ValueType;
            if (type == null || valueType == null)
                return false;
            if (type == typeof(Object) || type.FullName == "System.Object")
                return false;
            if (type.IsEnum)
                return false;
            bool val = !type.IsAssignableFrom(valueType);
            /*if (val) {
                context.Warnings.AppendFormat("{0} is not assignable from {1}\r\n",type.FullName,valueType.FullName);
            } */           
            return val;
        }


        public class XamlItemValue {

            public XamlItemValue(XamlItem item)
            {
                this.Item = item;
            }

            public XamlItem Item { get; set; }

            //public string Key { get; set; }
            public object Value { get; private set; }
            public Type ValueType { get; set; }
            public List<XamlItemExpression> Collection { get; set; }

            #region internal void Clear()
            public void Clear()
            {
                ValueType = null;
                //Key = null;
                Value = null;
                if (Collection != null) {
                    Trace.WriteLine(Item.Depth + "Collection Cleared");
                }
                Collection = null;
            }
            #endregion

            public void SetValue(object value) {
                if (Collection != null)
                {
                    Collection.Add(new XamlItemExpression
                    {
                        Expression = new CodePrimitiveExpression(value),
                        Item = null
                    });
                }
                else {
                    Value = value;
                }
            }

            #region internal void SetValue(CodePropertyReferenceExpression codePropertyReferenceExpression)
            public void SetValue(CodeExpression value, XamlItem refItem = null)
            {
                if (Collection != null)
                {
                    Trace.WriteLine(Item.Depth + "Added to Collection !!");
                    Collection.Add(new XamlItemExpression
                    { 
                        Expression = value,
                        Item = refItem ?? this.Item
                    });
                }
                else {
                    // collection is null...
                    Trace.WriteLine(Item.Depth + "Collection is Null");
                    Value = value;
                }
            }
            #endregion

            #region internal void CreateCollection()
            public void CreateCollection()
            {
                Trace.WriteLine(Item.Depth + "Collection Created");
                this.Collection = new List<XamlItemExpression>();
            }
            #endregion
}

    }


        public class XamlItemExpression {

            public XamlItem Item { get; set; }

            public CodeExpression Expression { get; set; }

        }
    
}
